package main

/*
* Content: atomic包-原子操作
* --------------------------------------------------
* golang中的原子操作atomic包: https://blog.csdn.net/weixin_40022980/article/details/126988531
* [go]原子操作atomic包简介: https://blog.csdn.net/alwaysrun/article/details/125023283
 */

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

var (
	x2  int64
	mx2 sync.Mutex
	wg2 sync.WaitGroup
)

// 普通函数, 并发不安全
func Add() {
	x2++
	wg2.Done()
}

// 互斥锁, 并发安全, 性能低于原子操作
func MxAdd() {
	mx2.Lock()
	x++
	mx2.Unlock()
	wg2.Done()
}

// 原子操作, 并发安全, 性能高于互斥锁, 只针对go中的一些基本数据类型使用
func AmAdd() {
	atomic.AddInt64(&x2, 1)
	wg2.Done()
}

func MyBagAtomic() {

	// atomic包-原子操作
	fmt.Println("--------------------atomic包-原子操作--------------------")

	// 原子操作 atomic 包
	// 加锁操作涉及到内核态的上下文切换, 比较耗时, 代价高,
	// 针对基本数据类型我们还可以使用原子操作来保证并发的安全,
	// 因为原子操作是 go语言提供的方法, 我们在 用户态 就可以完成, 因此性能比加锁操作更好

	start := time.Now()

	for i := 0; i < 10000; i++ {
		wg2.Add(1)
		//go Add()     // 普通版Add函数不是并发安全的                   - 结果:0  时间:2.5ms
		//go MxAdd()   // 加锁版Add函数，是并发安全的，但是加锁性能开销大 - 结果:10000  时间:3.1ms
		go AmAdd() // 原子操作版Add函数，是并发安全的，性能优于加锁版 - 结果:10000  时间:2.0ms
	}

	end := time.Now()

	// 同步等待
	wg2.Wait()

	fmt.Println(x2)

	// 计算总运行时间
	fmt.Println(end.Sub(start)) // 2.6ms

}
